﻿using System;
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.Security;
using PageTypeBuilder;
using TemplateFoundation.Configuration;
using TemplateFoundation.Tests.PageTypes;

namespace TemplateFoundation.Tests.Environment
{
    /// <summary>
    /// Used to create/clean up a page structure in the EPiServer site
    /// </summary>
    public static class PageStructure
    {
        /// <summary>
        /// Clears current content and creates a start page if necessary
        /// </summary>
        public static void SetupWebsiteContent()
        {
            // Clear old content
            EmptyWebsite();

            // Create new start page if one doesn't exist
            try
            {
                if (PageReference.StartPage==PageReference.RootPage)
                {
                    throw new PageNotFoundException("/");
                }

                DataFactory.Instance.GetPage(PageReference.StartPage);
            }
            catch (PageNotFoundException)
            {
                EPiServer.Configuration.Settings.Instance.PageStartId = CreateStartPage().ID;

                throw new EPiServerTestException("Start page was created, but test cannot proceed without re-initialization. Update 'PageStartId' in App.config and set it to '" + EPiServer.Configuration.Settings.Instance.PageStartId + "'.");
            }

            SetBasicSiteConfiguration();

            CreateNewsContainer("News");

            CreateTagsContainer("Tags", PageReference.RootPage);
        }

        public static PageReference CreateNewsContainer(string name)
        {
            var pageTypeId = PageTypeResolver.Instance.GetPageTypeID(typeof(NewsContainerPage));

            if (!pageTypeId.HasValue)
            {
                throw new EPiServerTestException("Unable to get the ID of the StandardPage page type");
            }

            var page = DataFactory.Instance.GetDefaultPageData(PageReference.StartPage, pageTypeId.Value);
            page.PageName = name;

            return DataFactory.Instance.Save(page, SaveAction.Publish, AccessLevel.NoAccess);
        }

        public static PageDataCollection CreateStandardPages(string name, PageReference parent, int count)
        {
            var pageTypeId = PageTypeResolver.Instance.GetPageTypeID(typeof (StandardPage));

            if (!pageTypeId.HasValue)
            {
                throw new EPiServerTestException("Unable to get the ID of the StandardPage page type");
            }

            var pages = new PageDataCollection(count);

            for (int i=0; i<count; i++)
            {
                var page = DataFactory.Instance.GetDefaultPageData(parent, pageTypeId.Value);
                page.PageName = string.Format("{0} {1}", name, i);

                DataFactory.Instance.Save(page, SaveAction.Publish, AccessLevel.NoAccess);

                pages.Add(page);
            }

            return pages;
        }

        public static PageReference CreateTagsContainer(string name, PageReference parent)
        {
            var pageTypeId = PageTypeResolver.Instance.GetPageTypeID(typeof(TagsContainerPage));

            if (!pageTypeId.HasValue)
            {
                throw new EPiServerTestException("Unable to get the ID of the TagsContainerPage page type");
            }

            var page = DataFactory.Instance.GetDefaultPageData(parent, pageTypeId.Value);
            page.PageName = name;

            var pageLink = DataFactory.Instance.Save(page, SaveAction.Publish, AccessLevel.NoAccess);

            Settings.Instance.TagsContainer = pageLink;

            return pageLink;
        }

        private static PageReference CreateStartPage()
        {
            var startPageTypeId = PageTypeResolver.Instance.GetPageTypeID(typeof(StartPage));

            if (!startPageTypeId.HasValue)
            {
                throw new EPiServerTestException("Unable to get the ID of the StartPage page type");
            }

            var startPage = (StartPage)DataFactory.Instance.GetDefaultPageData(PageReference.RootPage, startPageTypeId.Value);
            startPage.PageName = "Start";

            return DataFactory.Instance.Save(startPage, SaveAction.Publish, AccessLevel.NoAccess);
        }

        private static void SetBasicSiteConfiguration()
        {
            var startPage = (StartPage)DataFactory.Instance.GetPage(PageReference.StartPage).CreateWritableClone();

            // Set basic configuration for site
            startPage.DateFolderPageTypeId = PageTypeResolver.Instance.GetPageTypeID(typeof(NewsContainerPage));
            startPage.ArticlePageTypeId = PageTypeResolver.Instance.GetPageTypeID(typeof(ArticlePage));

            DataFactory.Instance.Save(startPage, SaveAction.Publish | SaveAction.ForceCurrentVersion, AccessLevel.NoAccess);
        }

        /// <summary>
        /// Removes all pages under the root, completely emptying the website
        /// </summary>
        public static void EmptyWebsite()
        {
            foreach (var page in DataFactory.Instance.GetChildren(PageReference.RootPage))
            {
                if (page.PageLink==PageReference.WasteBasket || page.PageLink==PageReference.StartPage)
                {
                    continue;
                }

                DataFactory.Instance.Delete(page.PageLink, true,AccessLevel.NoAccess);
            }

            foreach (var page in DataFactory.Instance.GetChildren(PageReference.StartPage))
            {
                DataFactory.Instance.Delete(page.PageLink, true, AccessLevel.NoAccess);
            }
        }

        /// <summary>
        /// Creates a number of empty articles
        /// </summary>
        /// <param name="count"></param>
        /// <param name="published"></param>
        public static void CreateArticles(int count, bool published)
        {
            for (int i = 0; i < count; i++)
            {
                CreateArticle(DateTime.Now.AddYears(-i - 1).AddMonths(-i - 1), published);
            }
        }

        /// <summary>
        /// Creates a new article page
        /// </summary>
        public static ArticlePage CreateArticle(DateTime startPublish, bool publish)
        {
            var newArticle = DataFactory.Instance.GetDefaultPageData(
                Settings.Instance.NewsContainer,
                PageTypeResolver.Instance.GetPageTypeID(typeof(ArticlePage)).Value);

            newArticle.StartPublish = startPublish;
            newArticle.PageName = "Article " + startPublish.ToShortDateString();

            DataFactory.Instance.Save(newArticle, publish ? SaveAction.Publish : SaveAction.CheckIn, AccessLevel.NoAccess);

            return (ArticlePage)DataFactory.Instance.GetPage(newArticle.PageLink);
        }

        /// <summary>
        /// Creates a new article page
        /// </summary>
        public static ArticlePage CreateArticle(DateTime startPublish, bool publish, PageReference author)
        {
            var newArticle = (ArticlePage)DataFactory.Instance.GetDefaultPageData(
                Settings.Instance.NewsContainer,
                PageTypeResolver.Instance.GetPageTypeID(typeof(ArticlePage)).Value);

            newArticle.StartPublish = startPublish;
            newArticle.PageContact = author;

            DataFactory.Instance.Save(newArticle, publish ? SaveAction.Publish : SaveAction.CheckIn, AccessLevel.NoAccess);

            return (ArticlePage)DataFactory.Instance.GetPage(newArticle.PageLink);
        }

        /// <summary>
        /// Creates a new person page
        /// </summary>
        public static PersonPage CreatePersonPage(string name)
        {
            var target = PageReference.IsNullOrEmpty(Settings.Instance.ContactsContainer)
                             ? PageReference.StartPage
                             : Settings.Instance.ContactsContainer;

            var contact = DataFactory.Instance.GetDefaultPageData(target, PageTypeResolver.Instance.GetPageTypeID(typeof(PersonPage)).Value);

            contact.PageName = name;

            DataFactory.Instance.Save(contact, SaveAction.Publish, AccessLevel.NoAccess);

            return (PersonPage)DataFactory.Instance.GetPage(contact.PageLink);
        }
    }
}
